<?php


namespace app\auth\middleware;

use Closure;
use Firebase\JWT\JWT;
use think\facade\Env;
use think\Response;

class Authorize
{
    /**
     * 在response header中生成授权签名
     * 后置中间件，如需触发，则需要在控制器中间件中指定即可
     * 2020-01-14：结构调整之后，此中间件暂时废弃，授权功能迁移至用户服务UserService中
     * @param $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next):Response
    {
        $response = $next($request);
        /**
         * 这个if意义重大，以前如果控制器抛出异常，那么后置中间件将停止工作（主要原因是抛出异常之后，执行渠道被切换）
         * 并且最后的异常处理将交由ExceptionHandle处理，此时可以理解为中间件是控制器方法执行链路中的一部分；
         * tp6以后，中间件策略调整，中间件的执行与控制器运行结果无关，无论结果怎样，
         * 都会按预期定义好的配置来运行中间件（如果控制器异常抛出，会先由ExceptionHandle处理）,
         * 因此以后在写某些后置中间件的时候，如果依赖于控制器的执行结果，那么最好先判断一下
         * PS：其实如果当某个中间件依赖于控制器action的执行结果时，可以考虑一下是否能转化成【事件/订阅】的机制来实现
         */
        if($response->getCode()>=300) return $response;

        $time = time();
        $data = $response->getData();
        $token = [
            'iat' => $time,//签发时间
            'nbf' => $time,//生效时间，比如设置time+30，表示当前时间30秒后才能使用
            'exp' => $time + 3600*24*30,//过期时间
            "iss" => $request->host(),//签发者
            'aud' => '*.'.$request->rootDomain(),//接收者
            'data' => [//自定义信息，不要定义敏感信息
                'id' => $data['id'],//例如用户主键id
//                'mobile' => $data['mobile'],//用户手机号
                                            //等等...
            ],
        ];

        $jwt = JWT::encode($token, Env::get('secret.jwt','BMW'));
        $response->header(['Authorization' => "Bearer $jwt"]);

        return $response;
    }
}